#ifndef _RRVERTEXATTRIB_HPP
#define _RRVERTEXATTRIB_HPP
/*-------------------------------------------------------------------------
 * drawElements Quality Program Reference Renderer
 * -----------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Vertex attribute fetch.
 *//*--------------------------------------------------------------------*/

#include "rrDefs.hpp"
#include "rrGenericVector.hpp"
#include "tcuVector.hpp"

namespace rr
{

enum VertexAttribType
{
	// Can only be read as floats
	VERTEXATTRIBTYPE_FLOAT = 0,
	VERTEXATTRIBTYPE_HALF,
	VERTEXATTRIBTYPE_FIXED,
	VERTEXATTRIBTYPE_DOUBLE,

	// Can only be read as floats, will be normalized
	VERTEXATTRIBTYPE_NONPURE_UNORM8,
	VERTEXATTRIBTYPE_NONPURE_UNORM16,
	VERTEXATTRIBTYPE_NONPURE_UNORM32,
	VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV,			//!< Packed format, only size = 4 is allowed

	// Clamped formats, GLES3-style conversion: max{c / (2^(b-1) - 1), -1 }
	VERTEXATTRIBTYPE_NONPURE_SNORM8_CLAMP,
	VERTEXATTRIBTYPE_NONPURE_SNORM16_CLAMP,
	VERTEXATTRIBTYPE_NONPURE_SNORM32_CLAMP,
	VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP,	//!< Packed format, only size = 4 is allowed

	// Scaled formats, GLES2-style conversion: (2c + 1) / (2^b - 1)
	VERTEXATTRIBTYPE_NONPURE_SNORM8_SCALE,
	VERTEXATTRIBTYPE_NONPURE_SNORM16_SCALE,
	VERTEXATTRIBTYPE_NONPURE_SNORM32_SCALE,
	VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE,	//!< Packed format, only size = 4 is allowed

	// can only be read as float, will not be normalized
	VERTEXATTRIBTYPE_NONPURE_UINT8,
	VERTEXATTRIBTYPE_NONPURE_UINT16,
	VERTEXATTRIBTYPE_NONPURE_UINT32,

	VERTEXATTRIBTYPE_NONPURE_INT8,
	VERTEXATTRIBTYPE_NONPURE_INT16,
	VERTEXATTRIBTYPE_NONPURE_INT32,

	VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV,	//!< Packed format, only size = 4 is allowed
	VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV,	//!< Packed format, only size = 4 is allowed

	// can only be read as integers
	VERTEXATTRIBTYPE_PURE_UINT8,
	VERTEXATTRIBTYPE_PURE_UINT16,
	VERTEXATTRIBTYPE_PURE_UINT32,

	VERTEXATTRIBTYPE_PURE_INT8,
	VERTEXATTRIBTYPE_PURE_INT16,
	VERTEXATTRIBTYPE_PURE_INT32,

	// reordered formats of GL_ARB_vertex_array_bgra
	VERTEXATTRIBTYPE_NONPURE_UNORM8_BGRA,
	VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA,
	VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA,
	VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA,

	// can be read as anything
	VERTEXATTRIBTYPE_DONT_CARE,					//!< Do not enforce type checking when reading GENERIC attribute. Used for current client side attributes.

	VERTEXATTRIBTYPE_LAST
};

/*--------------------------------------------------------------------*//*!
 * \brief Vertex attribute slot
 *
 * Vertex attribute type specifies component type for attribute and it
 * includes signed & normalized bits as well.
 *
 * Attribute size specifies how many components there are per vertex.
 * If size is 0, no components are fetched, ie. vertex attribute slot
 * is disabled.
 *
 * Divisor specifies the rate at which vertex attribute advances. If it is
 * zero, attribute is advanced per vertex. If divisor is non-zero, attribute
 * advances once per instanceDivisor instances.
 *
 * Pointer is used if not null, otherwise generic attribute is used instead
 * and in such case only DONT_CARE is valid attribute type.
 *//*--------------------------------------------------------------------*/
struct VertexAttrib
{
	VertexAttribType	type;				//!< Attribute component type.
	int					size;				//!< Number of components, valid range is [0,4].
	int					stride;				//!< Number of bytes two consecutive elements differ by. Zero works as in GL. Valid range is [0, inf).
	int					instanceDivisor;	//!< Vertex attribute divisor.
	const void*			pointer;			//!< Data pointer.
	GenericVec4			generic;			//!< Generic attribute, used if pointer is null.

	VertexAttrib (void)
		: type				(VERTEXATTRIBTYPE_FLOAT)
		, size				(0)
		, stride			(0)
		, instanceDivisor	(0)
		, pointer			(DE_NULL)
	{
	}

	VertexAttrib (VertexAttribType type_, int size_, int stride_, int instanceDivisor_, const void* pointer_)
		: type				(type_)
		, size				(size_)
		, stride			(stride_)
		, instanceDivisor	(instanceDivisor_)
		, pointer			(pointer_)
	{
	}

	template<typename ScalarType>
	explicit VertexAttrib (const tcu::Vector<ScalarType, 4>& generic_)
		: type				(VERTEXATTRIBTYPE_DONT_CARE)
		, size				(0)
		, stride			(0)
		, instanceDivisor	(0)
		, pointer			(DE_NULL)
		, generic			(generic_)
	{
	}
} DE_WARN_UNUSED_TYPE;

bool		isValidVertexAttrib		(const VertexAttrib& vertexAttrib);
// \todo [2013-04-01 pyry] Queries: isReadFloatValid(), isReadIntValid() ...

void		readVertexAttrib		(tcu::Vec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0);
void		readVertexAttrib		(tcu::IVec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0);
void		readVertexAttrib		(tcu::UVec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0);

// Helpers that return by value (trivial for compiler to optimize).

inline tcu::Vec4 readVertexAttribFloat (const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0)
{
	tcu::Vec4 v;
	readVertexAttrib(v, vertexAttrib, instanceNdx, vertexNdx, baseInstanceNdx);
	return v;
}

inline tcu::IVec4 readVertexAttribInt (const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0)
{
	tcu::IVec4 v;
	readVertexAttrib(v, vertexAttrib, instanceNdx, vertexNdx, baseInstanceNdx);
	return v;
}

inline tcu::UVec4 readVertexAttribUint (const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx, const int baseInstanceNdx = 0)
{
	tcu::UVec4 v;
	readVertexAttrib(v, vertexAttrib, instanceNdx, vertexNdx, baseInstanceNdx);
	return v;
}

} // rr

#endif // _RRVERTEXATTRIB_HPP
